package com.tfswx.jkgl.core.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.tfswx.jkgl.core.bean.Csdy;
import com.tfswx.jkgl.core.bean.Jkdy;
import com.tfswx.jkgl.core.bean.JkglRuntimeData;
import com.tfswx.jkgl.core.cscl.JmfsUtil;
import com.tfswx.jkgl.core.dto.ClcxInputDTO;
import com.tfswx.jkgl.core.dto.CsdygxInputDTO;
import com.tfswx.jkgl.core.dto.DeleteInputDTO;
import com.tfswx.jkgl.core.dto.SaveInputDTO;
import com.tfswx.jkgl.core.dto.SelectInputDTO;
import com.tfswx.jkgl.core.exception.AppException;
import com.tfswx.jkgl.core.service.ApiService;
import com.tfswx.jkgl.core.service.SjczService;
import com.tfswx.jkgl.core.task.ServiceTaskContextHolder;
import com.tfswx.jkgl.core.utils.*;
import com.tfswx.jkgl.core.yzfs.YzfsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author ricky
 * @date 2021/12/12
 */
@Slf4j
@Service
public class ApiServiceImpl implements ApiService {
    @Resource
    private JkglRuntimeData jkglRuntimeData;
    @Resource
    private SjczService sjczService;

    // boolean hasRedis = RedisUtils.hasRedis();

    @Override
    public Object apiPost(String jkbm, Object inputDTO) {
        // post请求
        return excute(jkbm, inputDTO, "POST");
    }

    @Override
    public Object apiGet(String jkbm, Object inputDTO) {
        // get请求
        return excute(jkbm, inputDTO, "GET");
    }

    @Override
    public Object excute(String jkbm, Object inputDTO) {
        // 根据request判断请求方式
        HttpServletRequest request = UrlUtil.getRequest();
        if (request != null) {
            return excute(jkbm, inputDTO, request.getMethod());
        }
        return excute(jkbm, inputDTO, "POST");
    }

    @Override
    public Object excute(String jkbm, Object inputDTO, String method) {
        Map<String, Jkdy> jkdyList = jkglRuntimeData.getJkdyList();
        if (jkdyList == null) {
            throw new RuntimeException("未加载接口数据【jkdyList】");
        }
        Jkdy jkglXtJkdy = jkdyList.get(jkbm);
        if (jkglXtJkdy == null) {
            throw new RuntimeException("接口【" + jkbm + "】未找到");
        }
        try {
            if (!method.equalsIgnoreCase(jkglXtJkdy.getQqfs())) {
                throw new RuntimeException("接口【" + jkbm + "】不支持【" + method + "】请求");
            }

            String clcxlx = jkglXtJkdy.getClcxlx();
            if (StringUtils.isBlank(clcxlx)) {
                throw new RuntimeException("接口【" + jkbm + "】未配置clcxlx");
            }
            String clcxcs = jkglXtJkdy.getClcxcs();
            if (StringUtils.isBlank(clcxcs)) {
                throw new RuntimeException("接口【" + jkbm + "】未配置clcxcs");
            }

            if ("wbcx".equals(clcxlx) && clcxcs.startsWith("http")) {
                HttpHeaders headers = new HttpHeaders();
                HttpServletRequest request = UrlUtil.getRequest();
                if (request != null) {
                    Enumeration<String> headerNames = request.getHeaderNames();
                    while (headerNames.hasMoreElements()) {
                        String s = headerNames.nextElement();
                        String header = request.getHeader(s);
                        headers.add(s, header);
                    }
                }
                HttpEntity<Object> httpEntity = new HttpEntity<>(inputDTO, headers);
                if ("post".equalsIgnoreCase(method)) {
                    return HttpUtil.postForObject(clcxcs, httpEntity, Object.class);
                } else if ("get".equalsIgnoreCase(method)) {
                    return HttpUtil.getForObject(clcxcs, httpEntity, Object.class);
                } else {
                    throw new RuntimeException("暂不支持【" + method + "】请求");
                }
            }


            // 获取入参配置与出参配置
            String rcpzStr = jkglXtJkdy.getRcpz();
            if (StringUtils.isBlank(rcpzStr)) {
                rcpzStr = "{}";
            }
            String ccpzStr = jkglXtJkdy.getCcpz();
            if (StringUtils.isBlank(ccpzStr)) {
                ccpzStr = "{}";
            }
            Csdy rcpz = JSON.parseObject(rcpzStr, Csdy.class);
            Csdy ccpz = JSON.parseObject(ccpzStr, Csdy.class);

            // 获取入参配置参数关系
            List<CsdygxInputDTO> csdygxInputDTOS = getCsgx(rcpz);

            String jklx = jkglXtJkdy.getJklx();

            Object value = inputDTO;
            int pageSize = 0;
            int pageNum = 0;
            String orderBy = null;
            // 分页查询前置处理
            if ("4".equals(jklx)) {
                if (!"List".equals(ccpz.getCslx())) {
                    throw new RuntimeException("出参参数类型不为列表，请检查！");
                }

                Map<String, Object> map = (Map<String, Object>) inputDTO;
                value = map.get("filter");
                if (value == null) {
                    throw new AppException("分页查询filter不能为空");
                }
                Object pageSize1 = map.get("pageSize");
                if (pageSize1 == null) {
                    throw new AppException("分页查询pageSize不能为空");
                }
                pageSize = Integer.parseInt(String.valueOf(pageSize1));
                Object pageNum1 = map.get("pageNum");
                if (pageNum1 == null) {
                    throw new AppException("分页查询pageNum不能为空");
                }
                pageNum = Integer.parseInt(String.valueOf(pageNum1));
                Object orderBy1 = map.get("orderBy");
                orderBy = orderBy1 == null ? null : String.valueOf(orderBy1);
                if (pageSize <= 0) {
                    throw new RuntimeException("pageSize-不能小于1");
                }
                if (pageNum <= 0) {
                    throw new RuntimeException("pageNum-不能小于1");
                }
            }

            // 入参验证
            List<String> errList = YzfsUtil.valid(rcpz, value);
            if (!errList.isEmpty()) {
                StringBuilder errStr = new StringBuilder();
                for (int i = 0; i < errList.size(); i++) {
                    errStr.append(i + 1).append("：").append(errList.get(i)).append(";");
                }
                throw new RuntimeException(errStr.toString());
            }
            // if (!errList.isEmpty()) {
            //     // StringBuilder errStr = new StringBuilder();
            //     Method excute = getClass().getMethod("excute", String.class, Object.class, String.class);
            //     MethodParameter parameter = new MethodParameter(excute, 0);
            //     BindingResult bindingResult = new BeanPropertyBindingResult(value, "inputDTO");
            //     MethodArgumentNotValidException methodArgumentNotValidException = new MethodArgumentNotValidException(parameter, bindingResult);
            //     for (int i = 0; i < errList.size(); i++) {
            //         ObjectError objectError = new ObjectError("inputDTO", errList.get(i));
            //         bindingResult.addError(objectError);
            //         // errStr.append(i + 1).append("：").append(errList.get(i)).append(";");
            //     }
            //     throw methodArgumentNotValidException;
            // }

            // 入参参数编码及过滤

            String id = IdUtil.fastSimpleUUID();
            value = JmfsUtil.encode(rcpz, value, "", null, true, id);

            // 外部请求处理
            if ("wbcx".equals(clcxlx)) {
                if (!"3".equals(jklx) && !"4".equals(jklx)) {
                    // throw new RuntimeException("外部程序只支持查询/分页查询，增删改的接口都选择查询！");
                }
                // 创建header
                // HttpHeaders headers = UrlUtil.getHeaders();

                if ("4".equals(jklx)) {
                    // 分页入参处理
                    Csdy.PageData fydx = new Csdy.PageData();
                    fydx.setOrderBy(orderBy);
                    fydx.setPageNum(pageNum);
                    fydx.setPageSize(pageSize);
                    fydx.setFilter(value);
                    value = fydx;
                }
                // HttpEntity<Object> httpEntity = new HttpEntity<>(value, headers);
                // Object o;
                // // 请求url组装
                // String url = UrlUtil.getUrl(clcxcs);
                // if ("GET".equalsIgnoreCase(method)) {
                //     o = HttpUtil.apiGetForObject(url, httpEntity, headers);
                // } else {
                //     o = HttpUtil.apiPostForObject(url, httpEntity, headers);
                // }
                if (StringUtils.isBlank(clcxcs)) {
                    throw new RuntimeException("外部程序，处理程序参数不能为空");
                }
                String[] split = clcxcs.split("\\.");
                if (split.length != 2) {
                    throw new RuntimeException("外部程序，处理程序参数错误");
                }
                Object o = ServiceUtil.excuteMethod(split[0], split[1], value);

                ServiceTaskContextHolder.startTask(value, id);

                if ("4".equals(jklx)) {
                    o = getPageResult(o, ccpz);
                } else {
                    // 出参参数编码及过滤
                    id = IdUtil.fastSimpleUUID();
                    o = JmfsUtil.encode(ccpz, o, "", null, false, id);
                    ServiceTaskContextHolder.startTask(o, id);
                }
                return o;
            } else {

                ClcxInputDTO clcxInputDTO = new ClcxInputDTO();
                clcxInputDTO.setClcxcs(clcxcs);
                clcxInputDTO.setClcxlx(clcxlx);
                if ("1".equals(jklx) || "2".equals(jklx)) {
                    // 新增及修改
                    SaveInputDTO saveInputDTO = new SaveInputDTO();
                    saveInputDTO.setCsgx(csdygxInputDTOS);
                    saveInputDTO.setClcx(clcxInputDTO);
                    saveInputDTO.setCsdy(value);
                    Object save = sjczService.save(saveInputDTO);
                    //
                    ServiceTaskContextHolder.startTask(value, id);
                    return save;
                } else if ("3".equals(jklx)) {
                    // 查询
                    SelectInputDTO selectInputDTO = new SelectInputDTO();
                    selectInputDTO.setCsgx(csdygxInputDTOS);
                    selectInputDTO.setClcx(clcxInputDTO);
                    selectInputDTO.setCsdy(value);
                    selectInputDTO.setCcpz(ccpz);
                    // String md5Hex = DigestUtils.md5Hex(JSON.toJSONString(selectInputDTO));
                    // md5Hex = "jkgl_cache_" + md5Hex;
                    // if (hasRedis) {
                    //     if (RedisUtils.exists(md5Hex)) {
                    //         log.info("从redis里面读取");
                    //         return RedisUtils.get(md5Hex);
                    //     }
                    // }
                    // log.info("从数据库读取");
                    Object select = sjczService.select(selectInputDTO);

                    // 出参参数编码及过滤
                    id = IdUtil.fastSimpleUUID();
                    Object encode = JmfsUtil.encode(ccpz, select, "", null, false, id);
                    ServiceTaskContextHolder.startTask(encode, id);
                    // if (hasRedis) {
                    //     RedisUtils.set(md5Hex, encode, 30L, TimeUnit.SECONDS);
                    // }
                    return encode;

                } else if ("4".equals(jklx)) {
                    // 分页查询
                    Csdy.PageData fydx = new Csdy.PageData();
                    fydx.setOrderBy(orderBy);
                    fydx.setPageNum(pageNum);
                    fydx.setPageSize(pageSize);
                    ccpz.setFydx(fydx);

                    SelectInputDTO selectInputDTO = new SelectInputDTO();
                    selectInputDTO.setCsgx(csdygxInputDTOS);
                    selectInputDTO.setClcx(clcxInputDTO);
                    selectInputDTO.setCsdy(value);
                    selectInputDTO.setCcpz(ccpz);
                    Object map = sjczService.select(selectInputDTO);
                    Object pageResult = getPageResult(map, ccpz);

                    return pageResult;
                } else if ("0".equals(jklx)) {
                    // 删除
                    DeleteInputDTO deleteInputDTO = new DeleteInputDTO();
                    deleteInputDTO.setCsgx(csdygxInputDTOS);
                    deleteInputDTO.setClcx(clcxInputDTO);
                    deleteInputDTO.setCsdy(value);
                    deleteInputDTO.setScbjh(rcpz.getScstjh());
                    try {
                        return sjczService.delete(deleteInputDTO);
                    } catch (Exception e) {
                        throw new RuntimeException("删除失败", e);
                    }
                }
            }

            return value;
        } finally {
            log.info("接口调用：{}", jkglXtJkdy.getJkms());
        }
    }

    /**
     * 分页出参编码及过滤
     *
     * @param o    分页出参
     * @param ccpz 出参配置
     * @return 处理后的分页出参
     */
    private Object getPageResult(Object o, Csdy ccpz) {
        Map<String, Object> select = new HashMap<>();
        Object total;
        List<Object> list;
        if (o instanceof PageInfo) {
            PageInfo<Object> map = (PageInfo<Object>) o;
            total = map.getTotal();
            list = new ArrayList<>(map.getList());
        } else {
            Map<String, Object> map = (Map<String, Object>) o;
            total = map.get("total");
            if (total != null) {
                total = Long.parseLong(String.valueOf(total));
            } else {
                total = 0;
            }
            Object list1 = map.get("list");
            if (list1 != null) {
                list = (List<Object>) list1;
            } else {
                list = new ArrayList<>();
            }
        }
        select.put("total", total);
        // 出参参数编码及过滤
        String id = IdUtil.fastSimpleUUID();
        Object encode = JmfsUtil.encode(ccpz, list, "", null, false, id);
        select.put("list", encode);
        ServiceTaskContextHolder.startTask(encode, id);
        return select;
    }

    private List<CsdygxInputDTO> getCsgx(Csdy cspz) {
        List<CsdygxInputDTO> list = new ArrayList<>();

        String csbm = cspz.getCsbm();
        if (StringUtils.isNotBlank(csbm)) {
            CsdygxInputDTO csdygxInputDTO = new CsdygxInputDTO();
            csdygxInputDTO.setCsbm(cspz.getCsbm());
            csdygxInputDTO.setStmc(cspz.getStmc());
            csdygxInputDTO.setZdmc(cspz.getZdmc());
            list.add(csdygxInputDTO);
        }
        List<Csdy> csdy = cspz.getCsdy();
        if (csdy == null) {
            return list;
        }
        for (Csdy csdy1 : csdy) {
            List<CsdygxInputDTO> csgx = getCsgx(csdy1);
            list.addAll(csgx);
        }
        return list;
    }
}
